﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Linq;
using AutoUpdateB.Info;
using Microsoft.Web.WebView2.Core;
using Microsoft.Web.WebView2.WinForms;
using FileInfo = AutoUpdateB.Info.FileInfo;

namespace AutoUpdateB
{
    public partial class MainForm : Form
    {
        string localConfigXMLPath = "config.xml";
        string remoteVersionXmlPath;
        string tempFolderPath = Path.Combine(@"./", "temp");
        string installPath;     // 主程序的安装目录，在窗体Load时获得。
        // 以下为 config.xml 中的内容。
        string startupPath;
        string softwareVersion; //更新程序当前版本
        string webInterface;
        string remoteUrl;       //远端资源服务器url
        string currentVersion;  //此为东东电竞主程序本地当前版本
        WebView2 webView;

        long totalFileSize;

        public MainForm()
        {
            InitializeComponent();
            progressBar.Visible = false;
            ReadConfigXml();
            InitializeAsync();
        }

        private async Task InitLogic()
        {
            try
            {
                // 从远程XML文件remoteVersionXmlPath直接下载文件中的文本内容。
                string remoteXmlContent = await AsyncDownloader.DownloadString(remoteVersionXmlPath);
                XDocument remoteDoc = XDocument.Parse(remoteXmlContent);

                string remoteVersionId = UpdateHelper.GetXmlElem(remoteDoc, "current_version_dir");

                // 如果本地启动路径不存在，则需要下载程序
                if (!File.Exists(startupPath))
                {
                    btn_start.LabelText = "下载";
                }
                // 与本地版本进行判断，如果需要更新则进行更新。
                else if (string.Compare(currentVersion, remoteVersionId) < 0)
                {
                    btn_start.LabelText = "更新";
                }
                else
                {
                    btn_start.LabelText = "启动";
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"更新检查失败: {ex.Message},将直接启动程序");
                btn_start.LabelText = "启动";
            }
        }



        async void InitializeAsync()
        {
            webView = new WebView2();
            webView.Dock = DockStyle.Fill;
            this.panel1.Controls.Add(webView);
            await webView.EnsureCoreWebView2Async(null);
            webView.CoreWebView2.Navigate(webInterface);
        }

        private void ReadConfigXml()
        {
            try
            {
                XmlDocument doc = new XmlDocument();
                doc.Load(localConfigXMLPath);

                XmlElement root = doc.DocumentElement;

                softwareVersion = root.SelectSingleNode("SoftwareVersion").InnerText;
                startupPath = root.SelectSingleNode("StartupPath").InnerText;
                webInterface = root.SelectSingleNode("WebInterface").InnerText;
                remoteUrl = root.SelectSingleNode("RemoteFileUrl").InnerText;
                remoteVersionXmlPath = Path.Combine(remoteUrl, "version_info.xml");
                softwareVersion = root.SelectSingleNode("SoftwareVersion").InnerText;
                currentVersion = root.SelectSingleNode("CurrentVersion").InnerText;
                lb_version.Text = softwareVersion;
            }
            catch (XmlException xmlEx)
            {
                Console.WriteLine($"XML解析错误: {xmlEx.Message}");
            }
        }

        /// <summary>
        /// 更新操作，先判断是否需要进行更新，如果需要更新就进行更新。
        /// </summary>
        /// <returns></returns>
        private async Task CheckUpdate()
        {
            try
            {
                string remoteXmlContent = await AsyncDownloader.DownloadString(remoteVersionXmlPath);
                XDocument remoteDoc = XDocument.Parse(remoteXmlContent);

                string remoteVersionId = UpdateHelper.GetXmlElem(remoteDoc, "current_version_dir");

                if (string.Compare(currentVersion, remoteVersionId) < 0)
                {
                    await UpdateProgram(remoteVersionId);
                }
                else
                {
                    lbStatus.Text = "已是最新版本";
                    btn_start.LabelText = "启动";
                }
            }
            catch (Exception ex)
            {
                btn_start.Text = "启动程序";
                MessageBox.Show("更新失败: " + ex.Message);
            }
        }



        //如果并未安装客户端，则全量下载文件
        private async Task DownLoadAllFile()
        {
            try
            {
                string remoteXmlContent = await AsyncDownloader.DownloadString(remoteVersionXmlPath);
                XDocument remoteDoc = XDocument.Parse(remoteXmlContent);
                string remoteVersionDir = UpdateHelper.GetXmlElem(remoteDoc, "current_version_dir");

                string remoteUpdateContent = await AsyncDownloader.DownloadString(Path.Combine(remoteUrl, remoteVersionDir, "update_files.xml"));
                XDocument remoteUpdateDoc = XDocument.Parse(remoteUpdateContent);
                progressBar.Visible = true;

                var latestVersionElement = remoteUpdateDoc.Descendants("version").FirstOrDefault();
                List<FileInfo> lf = UpdateHelper.ParseFullZip(latestVersionElement);

                // 下载所有文件
                await DownLoadFileFromList(remoteUpdateDoc, lf,SyncType.Full);

                // 下载完成后统一校验文件
                List<FileInfo> failedFiles = VarifyFile(lf, SyncType.Full);

                if (failedFiles.Count > 0)
                {
                    // 如果有文件校验失败，可以选择重新下载失败的文件，或者提示用户
                    MessageBox.Show("部分文件校验失败，请检查网络或重新尝试！");
                }
                else
                {
                    // 如果所有文件校验成功，继续后续操作
                    foreach (var fileInfo in lf)
                    {
                        string localPath = Path.Combine(tempFolderPath, Path.GetFileName(fileInfo.FilePath));
                        UpdateHelper.ExtraFile(localPath, installPath);
                    }

                    // 删除临时文件夹及其内容
                    Directory.Delete(tempFolderPath, true);
                    // 更新本地版本号
                    UpdateHelper.UpdateLocalXml(remoteVersionDir,localConfigXMLPath);
                    progressBar.Visible = false;
                    lbStatus.Text = "完成安装";
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"全量下载失败{ex.Message}");
            }
        }





        public async Task UpdateProgram(string remoteVersionDir)
        {
            try
            {
                string remoteXmlContent = await AsyncDownloader.DownloadString(Path.Combine(remoteUrl, remoteVersionDir, "update_files.xml"));
                XDocument remoteDoc = XDocument.Parse(remoteXmlContent);
                progressBar.Visible = true;
                lbStatus.Text = $"发现新版本 {remoteVersionDir}，开始下载...";

                var filelist = UpdateHelper.GetNeedUpdateFilelist(remoteDoc,installPath);

                // 下载所有文件
                await DownLoadFileFromList(remoteDoc, filelist,SyncType.Incremental);

                // 下载完成后统一校验文件
                List<FileInfo> failedFiles = VarifyFile(filelist, SyncType.Incremental);

                if (failedFiles.Count > 0)
                {
                    // 如果有文件校验失败，可以选择重新下载失败的文件，或者提示用户
                    MessageBox.Show("部分文件校验失败，请检查网络或重新尝试！");
                }
                else
                {
                    // 如果所有文件校验成功，继续后续操作
                    UpdateHelper.MoveFiles(tempFolderPath,installPath);
                    // 更新本地版本号
                    UpdateHelper.UpdateLocalXml(remoteVersionDir,localConfigXMLPath);
                    progressBar.Visible = false;
                    lbStatus.Text = "更新完成";
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        //全量更新验证
        private List<FileInfo> VarifyFile(List<FileInfo> lf, SyncType type)
        {
            progressBar.Value = 0;
            progressBar.Maximum = lf.Count;
            List<FileInfo> fail_list = new List<FileInfo>();
            string saveFilePath;
            foreach (var fileInfo in lf)
            {
                //增量更新和全量更新的两种模式
                if (type == SyncType.Full)
                {
                    saveFilePath = Path.Combine(tempFolderPath, Path.GetFileName(fileInfo.FilePath));
                }
                else
                {
                    saveFilePath = Path.Combine(tempFolderPath, fileInfo.FilePath);
                }

                if (UpdateHelper.VerifyFile(saveFilePath, fileInfo.Md5))
                {
                    progressBar.Value += 1;
                    lbStatus.Text = $"正在校验文件{Path.GetFileName(fileInfo.FilePath)} 验证成功！";
                }
                else
                {
                    fail_list.Add(fileInfo);
                    lbStatus.Text = $"{Path.GetFileName(fileInfo.FilePath)} 校验失败！";
                }
                Application.DoEvents();
            }
            //返回一个失败列表
            return fail_list;
        }


        /// <summary>
        /// 根据提供的文件列表下载文件
        /// </summary>
        /// <param name="remoteDoc">远端update_files.xml文件</param>
        /// <param name="lf">文件列表</param>
        /// <param name="type">更新方式（全量/增量）</param>
        private async Task DownLoadFileFromList(XDocument remoteDoc, List<FileInfo> lf,SyncType type)
        {
            if (lf.Count == 0)
                return;
            // 初始化下载变量
            totalFileSize = lf.Sum(f => f.FileSize);
            progressBar.Value = 0;

            // 创建一个任务列表来保存所有下载任务
            List<Task> downloadTasks = new List<Task>();
            AsyncDownloader _downloader = new AsyncDownloader();
            long receiveBytes = 0;
            // 订阅下载进度事件
            _downloader.ProgressChanged += (sender, args) =>
            {
                if (progressBar.InvokeRequired)
                {
                    progressBar.Invoke(new Action(() =>
                    {
                        receiveBytes += args.ReceivedBytes;
                        int value = (int)((receiveBytes / (double)totalFileSize) * 100);
                        lbStatus.Text = $"已下载 {value}%...";
                        progressBar.Value = value;
                    }));
                }
                else
                {
                    receiveBytes += args.ReceivedBytes;
                    int value = (int)((receiveBytes / (double)totalFileSize) * 100);
                    lbStatus.Text = $"已下载 {value}%...";
                    progressBar.Value = value;
                }
            };

            foreach (var fileInfo in lf)
            {
                string saveFilePath;
                string downloadUrl = Path.Combine(UpdateHelper.GetXmlElem(remoteDoc, "publish_url"),
                    fileInfo.FilePath);
                if (type == SyncType.Full)
                    saveFilePath = Path.Combine(tempFolderPath, Path.GetFileName(fileInfo.FilePath));
                else 
                    saveFilePath = Path.Combine(tempFolderPath, fileInfo.FilePath);
                // 将每个下载任务添加到任务列表中
                downloadTasks.Add(_downloader.StartDownloadAsync(downloadUrl, saveFilePath, false));
            }

            // 等待所有下载任务完成
            await Task.WhenAll(downloadTasks);
        }


        private async void btn_start_ClickAsync(object sender, EventArgs e)
        {
            try
            {
                btn_start.Enabled = false;
                // 根据按钮文本执行不同的操作
                switch (btn_start.LabelText)
                {
                    case "下载":
                        await DownLoadAllFile();
                        btn_start.LabelText = "启动";
                        btn_start.Enabled = true;
                        break;
                    case "更新":
                        await CheckUpdate();
                        btn_start.LabelText = "启动";
                        btn_start.Enabled = true;
                        break;
                    case "启动":
                        Process.Start(Path.Combine(installPath, startupPath));
                        this.Close();
                        break;
                    default:
                            break;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("操作失败: " + ex.Message);
                btn_start.Enabled = true;
            }

        }

        private Point mPoint;
        private void head_panel_MouseDown(object sender, MouseEventArgs e)
        {
            mPoint = new Point(e.X, e.Y);
        }

        private void head_panel_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
                this.Location = new Point(this.Location.X + e.X - mPoint.X,
                    this.Location.Y + e.Y - mPoint.Y);
        }

        private void btn_close_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void btn_min_Click(object sender, EventArgs e)
        {
            this.WindowState = FormWindowState.Minimized;
        }

        private async void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (webView != null && webView.CoreWebView2 != null)
            {
                await webView.CoreWebView2.Profile.ClearBrowsingDataAsync(CoreWebView2BrowsingDataKinds.AllProfile);
            }
        }


        private async void MainForm_Load(object sender, EventArgs e)
        {
            //默认主程序安装目录是与启动器同级目录
            installPath = Environment.CurrentDirectory;
            await InitLogic();
            Console.WriteLine(installPath);
        }

    }
}